package com.hmily.spring.samples.scanner;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;
import java.util.Set;

/**
 * <h1>扫描器。</h1>
 *
 * @author hmilyylimh
 * ^_^
 * @version 0.0.1
 * ^_^
 * @date 2021-10-31
 */
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {

    private MapperFactoryBean mapperFactoryBean = new MapperFactoryBean();

    public ClassPathMapperScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }

    public void registerFilters(){
        addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
    }

    @Override
    public Set<BeanDefinitionHolder> doScan(String... basePackages) {
        // 1. 调用父类方法得到所有的BeanDefinition集合
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        if (beanDefinitions == null || beanDefinitions.isEmpty()) {
            return beanDefinitions;
        }

        // 2. 针对BeanDefinition集合进行改造，目的是为了代理XxxMapper这样的接口类
        reProcessBeanDefinitions(beanDefinitions);
        return beanDefinitions;
    }

    private void reProcessBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        for (BeanDefinitionHolder holder : beanDefinitions) {
            GenericBeanDefinition beanDefinition = (GenericBeanDefinition)holder.getBeanDefinition();

            beanDefinition.getConstructorArgumentValues()
                    .addGenericArgumentValue(beanDefinition.getBeanClassName());
            beanDefinition.setBeanClass(mapperFactoryBean.getClass());
            beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        }
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        AnnotationMetadata metadata = beanDefinition.getMetadata();
        return metadata.isInterface();
    }

//    @Override
//    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
//        return true;
//    }
}
